<?php

$config = include './config/config.php';
$m = new Model($config);
// 注意要清空options数组。在query和exec中


//使用一个没有定义的方法
var_dump($m->getByName('樱桃'));

// max测试
// var_dump($m->table('wuxianji')->max('id'));

// update测试
// $data = [
// 	'name' => '樱桃',
// 	'parent_id' => 9
// ];
// $re = $m->table('wuxianji')->where('id=16')->update($data);
// var_dump($re);

// delete测试
// $re = $m->table('wuxianji')->where('id=19')->delete();
// var_dump($re);

// insert测试
// $data = [
// 	'name' => '樱桃',
// 	'parent_id' => 9
// ];
// $re = $m->table('wuxianji')->insert($data);
// var_dump($re);

// select测试
// $res = $m->table('wuxianji')->where('id>12')->limit("0,5")->order('id desc')->field('id,name')->select();
// $res2 = $m->table('wuxianji')->field('id,name')->select();
// var_dump($res);
// echo "-------------------------------------";
// var_dump($res2);


class Model
{
	// 数据库host
	protected $host;
	// 数据库用户名
	protected $user;
	// 数据库密码
	protected $pwd;
	// 数据库编码
	protected $charset;
	// 数据库名
	protected $dbName;
	// 数据表前缀
	protected $prefix;

	// 数据表名
	protected $tableName = 'wuxianji';
	// 返回的数据库资源
	protected $link;

	// 操作数据
	protected $options;
	// SQL
	protected $sql;

	// 构造方法，初始化成员变量
	function __construct($config)
	{
		$this->host = $config['DB_HOST'];
		$this->user = $config['DB_USER'];
		$this->pwd = $config['DB_PWD'];
		$this->charset = $config['DB_CHARSET'];
		$this->dbName = $config['DB_NAME'];
		$this->prefix = $config['DB_PREFIX'];

		// 连接数据库
		$this->link = $this->connect();

		// 获取数据表名
		$this->tabelName = $this->getTableName();

		// 初始化options
		$this->initOptions();
	}

	// 连接数据库
	protected function connect()
	{
		$link = mysqli_connect($this->host, $this->user, $this->pwd);
		if(!$link){
			die("数据库连接失败");
		}
		// 选择数据库
		mysqli_select_db($link, $this->dbName);
		// 设置编码
		mysqli_set_charset($link, $this->charset);
		return $link;
	}
	// 获取数据表名
	protected function getTableName()
	{
		// 1.如果有传递表名，就使用使用它
		if(!empty($this->tableName)){
			return $this->prefix.$this->tableName;
		}
		// 2.根据类名得到表名 user -> UserModel
		$className = get_class($this);
		$table = strtolower(substr($className, 0, -5));
		return $this->prefix.$table;
	}

	protected function initOptions()
	{
		$arr = ['table', 'where', 'field', 'order', 'group', 'having', 'limit'];
		foreach ($arr as $value) {
			$this->options[$value] = '';
			if($value == 'table'){
				$this->options[$value] = $this->tableName;
			}else if ($value == 'field'){
				$this->options[$value] = '*';
			}
		}
	}
	
	// field
	function field($field)
	{
		if(!empty($field)){
			if(is_string($field)){
				$this->options['field'] = $field;
			}else if (is_array($field)) {
				$this->options['field'] = join(",", $field);
			}
		}
		return $this;
	}
	// table
	function table($table)
	{
		if(!empty($table)){
			$this->options['table'] = $table;
		}
		return $this;
	}
	// where
	function where($where)
	{
		if(!empty($where)){
			if(is_string($where)){
				$this->options['where'] = 'where '.$where;
			}else if(is_array($where)){
				$this->options['where'] = 'where '.join(' ' ,$where);
			}
		}
		return $this;
	}
	// group
	function group($group)
	{
		if(!empty($group)){
			$this->options['group'] = 'group by '.$group;
		}
		return $this;
	}
	// having
	function having($having)
	{
		if(!empty($having)){
			$this->options['having'] = 'having '.$having;
		}
		return $this;
	}
	// order
	function order($order)
	{
		if(!empty($order)){
			$this->options['order'] = 'order by '.$order;
		}
		return $this;
	}
	// limit
	function limit($limit)
	{
		if(!empty($limit)){
			if(is_string($limit)){
				$this->options['limit'] = 'limit '.$limit;
			}else if(is_array($limit)){
				$this->options['limit'] = 'limit '.join(',', $limit);
			}
		}
		return $this;
	}
	// select
	function select()
	{
		$sql = 'select %FIELD% from %TABLE% %WHERE% %GROUP% %HAVING% %ORDER% %LIMIT%';
		$sql = str_replace(
			['%FIELD%', '%TABLE%', '%WHERE%', '%GROUP%', '%HAVING%', '%ORDER%', '%LIMIT%'], 
			[$this->options['field'], $this->options['table'], $this->options['where'], $this->options['group'], $this->options['having'], $this->options['order'], $this->options['limit']], 
			$sql);
		// 保存SQL语句
		$this->sql = $sql;
		// 执行SQL语句
		return $this->query($sql);
	}

	// query
	protected function query($sql)
	{
		// 清空options数组
		$this->initOptions();
		$result = mysqli_query($this->link, $sql);
		if($result && mysqli_affected_rows($this->link)){
			while ($data = mysqli_fetch_assoc($result)) {
				$newData[] = $data;
			}
			return $newData;
		}
		return false;
	}

	// exec
	protected function exec($sql, $parse = false)
	{
		// 清空options数组
		$this->initOptions();
		$result = mysqli_query($this->link, $sql);
		if($result && mysqli_affected_rows($this->link)){
			if($parse){
				return mysqli_insert_id($this->link);
			}else{
				return mysqli_affected_rows($this->link);
			}
		}
		return false;
	}

	// update 表名 set 字段名=值 where
	function update($data)
	{
		// 值里面拼接引号
		$data = $this->praseValue($data);
		$value = $this->praseUpdate($data);
		$sql = 'update %TABLE% set %VALUE% %WHERE%';
		$sql = str_replace(
			['%TABLE%', '%VALUE%', '%WHERE%'], 
			[$this->options['table'], $value, $this->options['where']], 
			$sql);
		// 保存SQL语句
		$this->sql = $sql;
		// 执行SQL语句
		return $this->exec($sql);
	}
	
	// insert into 表名 (字段名) values (值)
	function insert($data)
	{
		// 处理数组，将各个值添加引号
		$data = $this->praseValue($data);
		$keys = array_keys($data);
		$values = array_values($data);
		$sql = 'insert into %TABLE% (%KEY%) values (%VALUE%)';
		$sql = str_replace(
			['%TABLE%', '%KEY%', '%VALUE%'],
			[$this->options['table'], join(',', $keys), join(',', $values)], 
			$sql);
		// 保存SQL语句
		$this->sql = $sql;
		// 执行SQL语句
		return $this->exec($sql, true);
	}
	
	// delete from 表名 where
	function delete()
	{
		$sql = 'delete from %TABLE% %WHERE%';
		$sql = str_replace(['%TABLE%', '%WHERE%'], [$this->options['table'], $this->options['where']], $sql);
		return $this->exec($sql);
	}

	// 获取最大的值
	function max($field)
	{
		// $result = $this->field('max('.$field.') as max')->select();
		// return $result[0]['max'];

		$this->options['field'] = 'max('.$field.') as max';
		return $this->select()[0]['max'];
	}

	// 传入关联数组，用=拼接键值，返回字符串
	protected function praseUpdate($data)
	{
		foreach ($data as $key => $value) {
			$newData[] = $key."=".$value;
		}
		return join(",", $newData);
	}

	// 传入关联数组，返回有引号的数组值
	protected function praseValue($data)
	{
		foreach ($data as $key => $value) {
			$newData[$key] = '"'.$value.'"';
		}
		return $newData;
	}

	// 暴露成员变量sql
	public function __get($name)
	{
		if($name == 'sql'){
			return $this->sql;
		}
		return false;
	}

	function __destruct()
	{
		mysqli_close($this->link);
	}

	// __call，当调用一个不存在的方法时调用，两个参数，1.方法名，2.参数
	// getByName
	function __call($fun, $args)
	{
		// 获取前5个字符
		$str = substr($fun, 0, 5);
		// 获取字段名
		$field = strtolower(substr($fun, 5));
		// 判断前五个字符是否是getBy
		if($str == 'getBy'){

			return $this->where($field.'="'.$args[0].'"')->select();
		}
		return false;
	}
}